#include "FabricaRecursosAlmacenamiento.h"
#include "RecursoDeAlmacenamiento.h"
#include "../estrategiaRecurso/Archivo.h"
#include "../estrategiaRecurso/Buffer.h"
#include "../recursoDeAlmacenamiento/FabricaCompuestos.h"
#include "../compresor/FabricaContenedorComprimido.h"
#include "../compresor/Aritmetico.h"
#include "../estrategiaAlmacenamiento/EstrategiaAlmacenamiento.h"
#include "../estrategiaRecurso/EstrategiaRecurso.h"
#include "../estrategiaRecurso/EstrategiaRecursoUnAlmacenamiento.h"
#include "../estrategiaRecurso/EstrategiaRecursoEscrituraDiferida.h"
#include "../estrategiaAlmacenamiento/EstrategiaAlmacenamientoRegistro.h"
#include "../estrategiaRecurso/EstrategiaRecursoEscrituraDirecta.h"
#include "../estrategiaAlmacenamiento/EstrategiaAlmacenamientoBloques.h"
#include "../indices/Indice.h"
#include "../recursoDeAlmacenamiento/RecursoDeAlmacenamientoDirecto.h"
#include "../recursoDeAlmacenamiento/RecursoDeAlmacenamientoIndexado.h"

FabricaRecursosAlmacenamiento::FabricaRecursosAlmacenamiento() {

}

FabricaRecursosAlmacenamiento::~FabricaRecursosAlmacenamiento() {

}

RecursoDeAlmacenamiento* FabricaRecursosAlmacenamiento::crearRecursoArchivoRegistros(
		const string& path, cantBytes tamanioComp, tipo_estrategia_recurso tipoEstrategiaRecurso) {

	Archivo* archivo = new Archivo(path);

	EstrategiaRecurso* esRecurso;

	if (tipoEstrategiaRecurso == SIN_BUFFER) {
		esRecurso = new EstrategiaRecursoUnAlmacenamiento(archivo);
	} else if (tipoEstrategiaRecurso == DIRECTA) {
		esRecurso = new EstrategiaRecursoEscrituraDirecta(archivo);
	} else {
		esRecurso = new EstrategiaRecursoEscrituraDiferida(archivo,tamanioComp + 1);
	}


	EstrategiaAlmacenamientoRegistro* esRegistro =
			new EstrategiaAlmacenamientoRegistro(tamanioComp);
	RecursoDeAlmacenamiento* recurso = new RecursoDeAlmacenamiento(esRegistro, esRecurso);
	esRegistro->setRecurso(recurso);
	recurso->inicializar();
	return recurso;
}

FabricaRecursosAlmacenamiento* FabricaRecursosAlmacenamiento::getFabrica() {

	static FabricaRecursosAlmacenamiento instancia;
	return &instancia;
}

RecursoDeAlmacenamiento* FabricaRecursosAlmacenamiento::crearRecursoArchivoBloques(
		const string& path, cantBytes tamanioBloque, tipo_estrategia_recurso tipoEstrategiaRecurso,tipo_fabrica_compuesto tipoFabricaCompuesto) {

	Archivo* archivo = new Archivo(path);

	EstrategiaRecurso* esRecurso;

	if (tipoEstrategiaRecurso == SIN_BUFFER) {
		esRecurso = new EstrategiaRecursoUnAlmacenamiento(archivo);
	} else if (tipoEstrategiaRecurso == DIRECTA) {
		esRecurso = new EstrategiaRecursoEscrituraDirecta(archivo);
	} else {
		esRecurso = new EstrategiaRecursoEscrituraDiferida(archivo,tamanioBloque);
	}

	FabricaCompuestos* fabrica = NULL;

	if (tipoFabricaCompuesto == FABRICA_BLOQUES) {
		fabrica = new FabricaCompuestos();
	} else if (tipoFabricaCompuesto == FABRICA_BLOQUES_COMPRIMIDOS) {
		fabrica = new FabricaContenedorComprimido(new Aritmetico());
	}

	EstrategiaAlmacenamientoBloques* esBloques =
			new EstrategiaAlmacenamientoBloques(tamanioBloque,fabrica);
	RecursoDeAlmacenamiento* recurso = new RecursoDeAlmacenamiento(esBloques, esRecurso);
	esBloques->setRecurso(recurso);
	recurso->inicializar();

	return recurso;
}

RecursoDeAlmacenamientoDirecto* FabricaRecursosAlmacenamiento::crearRecursoAccesoDirecto(
		const string& path, cantBytes tamanioReg, tipo_estrategia_recurso tipoEstrategiaRecurso) {

	Archivo* archivo = new Archivo(path);

	EstrategiaRecurso* esRecurso;

	if (tipoEstrategiaRecurso == SIN_BUFFER) {
		esRecurso = new EstrategiaRecursoUnAlmacenamiento(archivo);
	} else if (tipoEstrategiaRecurso == DIRECTA) {
		esRecurso = new EstrategiaRecursoEscrituraDirecta(archivo);
	} else {
		esRecurso = new EstrategiaRecursoEscrituraDiferida(archivo,tamanioReg + 1);
	}

	EstrategiaAlmacenamientoRegistro* esRegistro =
			new EstrategiaAlmacenamientoRegistro(tamanioReg);
	RecursoDeAlmacenamientoDirecto* recurso =
			new RecursoDeAlmacenamientoDirecto(esRegistro, esRecurso);
	esRegistro->setRecurso(recurso);
	recurso->inicializar();

	return recurso;
}

RecursoDeAlmacenamientoIndexado* FabricaRecursosAlmacenamiento::crearRecursoIndexadoBloques(const string& path,
		cantBytes tamanioBloque, Indice* indice, tipo_estrategia_recurso tipoEstrategiaRecurso,tipo_fabrica_compuesto tipoFabricaCompuesto) {

	Archivo* archivo = new Archivo(path);

	EstrategiaRecurso* esRecurso;
	if (tipoEstrategiaRecurso == SIN_BUFFER) {
		esRecurso = new EstrategiaRecursoUnAlmacenamiento(archivo);
	} else if (tipoEstrategiaRecurso == DIRECTA) {
		esRecurso = new EstrategiaRecursoEscrituraDirecta(archivo);
	} else {
		esRecurso = new EstrategiaRecursoEscrituraDiferida(archivo,tamanioBloque);
	}

	FabricaCompuestos* fabrica = NULL;

	if (tipoFabricaCompuesto == FABRICA_BLOQUES) {
		fabrica = new FabricaCompuestos();
	} else if (tipoFabricaCompuesto == FABRICA_BLOQUES_COMPRIMIDOS) {
		fabrica = new FabricaContenedorComprimido(new Aritmetico());
	}

	EstrategiaAlmacenamientoBloques* esBloques =
			new EstrategiaAlmacenamientoBloques(tamanioBloque,fabrica);


	RecursoDeAlmacenamientoIndexado* recurso = new RecursoDeAlmacenamientoIndexado(
			esBloques, esRecurso, indice);
	esBloques->setRecurso(recurso);
	recurso->inicializar();
	if(indice->estaVacio()){
		indice->indexar(recurso);
	}
	return recurso;
}

RecursoDeAlmacenamientoIndexado* FabricaRecursosAlmacenamiento::crearRecursoIndexadoRegistros(const string& path,
		cantBytes tamanioReg, Indice* indice, tipo_estrategia_recurso tipoEstrategiaRecurso) {

	Archivo* archivo = new Archivo(path);

	EstrategiaRecurso* esRecurso;
	if (tipoEstrategiaRecurso == SIN_BUFFER) {
		esRecurso = new EstrategiaRecursoUnAlmacenamiento(archivo);
	} else if (tipoEstrategiaRecurso == DIRECTA) {
		esRecurso = new EstrategiaRecursoEscrituraDirecta(archivo);
	} else {
		esRecurso = new EstrategiaRecursoEscrituraDiferida(archivo,tamanioReg + 1);
	}

	EstrategiaAlmacenamientoRegistro* esRegistro =
			new EstrategiaAlmacenamientoRegistro(tamanioReg);
	RecursoDeAlmacenamientoIndexado* recurso =
			new RecursoDeAlmacenamientoIndexado(esRegistro, esRecurso, indice);
	esRegistro->setRecurso(recurso);

	recurso->inicializar();

	if(indice->estaVacio()){
		indice->indexar(recurso);
	}

	return recurso;
}
